/** 
 *  @file
 *  @brief   广义弹簧阻尼结构单元
 *  @author  chentielu yuanchenxi duweixing
 *  @date    2024.5.9
 *  @version v1.0
 *  @par Copyright(c):  ShenGong  Simulation corporation
 */

#pragma once
#include "Utility/Algebra/Matrix.h"
#include "DataStructure/Common/Out.h"
#include "DataStructure/Common/Real.h"
#include "DataStructure/Input/Node/NodeData.h"
#include "DataStructure/Input/Element/CBUSHData.h"
#include "DBManager/IService/Input/Property/IPBUSHService.h"
#include "../Common/ElementCalculatorExport.h"
#include "../Interface/IElementCalculator.h"

SG_FEMSOLVER_ELEMENT_NAMESPACE_OPEN

class ElementCalculator_DECLSPEC BushCalculator : public SG::FEMSolver::Element::IElementCalculator
{
public:
    BushCalculator () = default;
    virtual ~BushCalculator () = default;

    /** @brief 计算单元变换矩阵：单元坐标系到位移输出坐标系变换 + 偏置变换
     * 
     *  @param [in] nEleNodes 单元节点数
     *  @param [in] element 单元数据
     *  @param [in] nodeSet 单元节点数据
     *  @param [in] orienNode 单元朝向节点数据，如果使用朝向节点
     *  @param [in] K 刚度系数
     *  @param [out] isSpecifyEleCoordSys 是否指定单元坐标系、朝向节点或者朝向矢量
     *  @param [out] TEle 单元变换矩阵：单元坐标系到位移输出坐标系变换
     *  @param [out] TEleOffset 单元变换矩阵：单元坐标系到位移输出坐标系变换 + 偏置变换
     */
    static void ComputeElementTrans
    (
    const std::size_t                                    nEleNodes,
    const SG::DataStructure::FEM::CBUSHData&             element,
    const std::vector<SG::DataStructure::FEM::NodeData>& nodeSet,
    const SG::DataStructure::FEM::NodeData&              orienNode,
    const SG::DataStructure::Common::Real*&              K,
    _OUT bool                                            isSpecifyEleCoordSys,
    _OUT SG::Algebra::Matrixd&                           TEle,
    _OUT SG::Algebra::Matrixd&                           TEleOffset
    );

    /** @brief 计算单元坐标系下单元刚度矩阵
     * 
     *  @param [in] nEleNodes 单元节点数
     *  @param [in] property 单元属性
     *  @param [out] kl 单元坐标系下单元刚度矩阵
     */
    static void ComputeStiffness
    (
    const std::size_t                        nEleNodes,
    const SG::DataStructure::FEM::PBUSHData& property,
    _OUT SG::Algebra::Matrixd&               kl
    );

    /** @brief 计算单元坐标系下单元质量矩阵
     * 
     *  @param [in] nEleNodes 单元节点数
     *  @param [in] element 单元数据
     *  @param [in] nodeSet 单元节点数据
     *  @param [in] property 单元属性
     *  @param [out] lumpedM 单元坐标系下单元质量矩阵
    */
    static void ComputeMass
    (
    const std::size_t                                    nEleNodes,
    const SG::DataStructure::FEM::CBUSHData&             element,
    const std::vector<SG::DataStructure::FEM::NodeData>& nodeSet,
    const SG::DataStructure::FEM::PBUSHData&             property,
    _OUT SG::Algebra::Matrixd&                           lumpedM
    );

    /**
     * @brief 计算单元内力
     * 
     * @param [in] nEleNodes 单元节点数
     * @param [in] kl 单元坐标系单元刚度矩阵
     * @param [in] TEle 单元变换矩阵：单元坐标系到位移输出坐标系变换 + 偏置变换
     * @param [in] elementDisplacement 位移输出坐标系单元位移
     * @param [out] elementInternalForce 单元内力
     */
    static void ComputeElementInternalForce
    (
    const std::size_t           nEleNodes,
    const SG::Algebra::Matrixd& kl,
    const SG::Algebra::Matrixd& TEle,
    const SG::Algebra::Matrixd& elementDisplacement,
    _OUT SG::Algebra::Matrixd&  elementInternalForce
    );

    /**
     * @brief    计算单元应变
     * 
     * @param    property 单元属性
     * @param    nEleNodes 单元节点数
     * @param    TEle 单元变换矩阵：单元坐标系到位移输出坐标系变换 + 偏置变换
     * @param    elementDisplacement 位移输出坐标系单元位移
     * @param    elementStrain 单元应变
     * @author   Du Weixing
     * @date     2024.12.18
     */
    static void ComputeElementStrain
    (
    const SG::DataStructure::FEM::PBUSHData& property,
    const std::size_t                        nEleNodes,
    const SG::Algebra::Matrixd&              TEle,
    const SG::Algebra::Matrixd&              elementDisplacement,
    _OUT SG::Algebra::Matrixd&               elementStrain
    );

    /**
     * @brief 计算单元应力
     * 
     * @param [in] elementInternalForce 单元内力
     * @param [in] property 单元属性
     * @param [out] elementStress 单元应力
     */
    static void ComputeElementStress
    (
    const SG::Algebra::Matrixd&              elementInternalForce,
    const SG::DataStructure::FEM::PBUSHData& property,
    _OUT SG::Algebra::Matrixd&               elementStress
    );

    virtual void Initialize (SG::DataStructure::FEM::ElementTypes type) override;
    virtual void ComputeElementMatries (const SG::DBManager::DBServiceFactorySP dbServiceFactory) override;
    virtual void DataRecovery (const SG::DBManager::DBServiceFactorySP dbServiceFactory, int subcaseId, SG::DataStructure::Common::Real time, const std::vector<SG::DataStructure::Common::Real>& globalDisplacement) override;
    virtual void ComputeStressStiffness (const SG::DBManager::DBServiceFactorySP dbServiceFactory, int staticSubId) override;

    static ElementCalculatorSP Create () {return std::make_shared<BushCalculator> ();}

private:
    SG::DataStructure::FEM::ElementTypes m_type;
};

SG_FEMSOLVER_ELEMENT_NAMESPACE_CLOSE